package com.apimarket.service;

import com.apimarket.dao.ApplyMapper;
import com.apimarket.entity.ApiSet;
import com.apimarket.entity.Apply;
import com.apimarket.entity.kong.KeyAuthCredential;
import com.apimarket.entity.kong.Plugin;
import com.apimarket.enums.ExceptionEnum;
import com.apimarket.exception.AMException;
import com.apimarket.exception.NetContextException;
import com.apimarket.util.kong.KongOperationType;
import com.apimarket.util.kong.KongPlugin;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Transactional
@Service
public class ApplyService {
    Logger logger= LoggerFactory.getLogger(ApplyService.class);
    @Autowired(required = false)
    private ApplyMapper mapper;
    @Autowired
    private ApiService apiService;
    @Autowired
    private PluginService pluginService;
    @Autowired
    private ConsumerService consumerService;
    @Autowired
    private KongPlugin kongPlugin;

    public List<Apply> queryList(Apply entity) {
        List<Apply> list = mapper.queryList(entity);
        if(CollectionUtils.isEmpty(list)){
            throw new AMException(ExceptionEnum.Apply_NOT_FOUND);
        }
        return list;
    }

    public void insert(Apply entity) {
        int sign;
        try {
            sign=mapper.insert(entity);
        }catch (Exception e
        ){
            throw new AMException(ExceptionEnum.Apply_INSERT_ERROR);
        }
        if(sign!=1){
            throw new AMException(ExceptionEnum.Apply_INSERT_ERROR);
        }
    }

    public void update(Apply entity) {
        int sign;
        try {
            sign=mapper.update(entity);
        }catch (Exception e){
            throw new AMException(ExceptionEnum.Apply_UPDATE_ERROR);
        }
        if(sign!=1){
            throw new AMException(ExceptionEnum.Apply_UPDATE_ERROR);
        }
    }

    public void delete(Integer id) {
        int sign;
        try {
            sign=mapper.delete(id);
        }catch (Exception e){
            throw new AMException(ExceptionEnum.Apply_DELETE_ERROR);
        }
        if(sign!=1){
            throw new AMException(ExceptionEnum.Apply_DELETE_ERROR);
        }
    }

    public void addApply(Apply apply, MultipartFile picFile) {
        logger.info("文件是否为null:"+(picFile==null));
        if(picFile!=null)
            logger.info("文件大小："+ picFile.getSize());
        if(picFile.getSize()==0){
            throw new AMException(ExceptionEnum.File_NOT_UPLOAD);
        }
        if(!StringUtils.isEmpty(apply.getSetId())&&apply.getTimes()==null){
            //如果是接口集的申请，就必须要传使用次数
            //因为apply的默认初始化时候会传使用次数
            throw new AMException(ExceptionEnum.Apply_SET_ADD_TIMES);
        }
        //上传的多张图片需要先存储到服务器
        StringBuilder sb=new StringBuilder("");
        sb.append(apiService.SaveApplyFile(picFile));
        //加这个是因为前端代码写好了，方便他不用改
        sb.append(";");
        /*try{
            for(MultipartFile file:picFile){
                //上传存储图片，返回的是存储的最终路径
                //多个图片存储的路径用;分割
                sb.append(apiService.SaveFile(file)).append(";");
            }
        }catch (StringIndexOutOfBoundsException e){
            throw new AMException(ExceptionEnum.File_NOT_UPLOAD);
        }*/
        apply.setPicUrls(sb.toString());
        apply.setDate(new Date());
        mapper.insert(apply);
    }

    public PageInfo<Apply> getPageObject(Apply entity, Integer pageSize, Integer pageCurrent) {
        // 1.参数校验
        if(pageCurrent==null||pageCurrent<1)
            throw new IllegalArgumentException("当前页码有误");
        if(pageSize==null||pageSize<1)
            throw new IllegalArgumentException("当前页显示数目有误");
        String orderBy="date desc";
        //传入查询第几页，以及显示多少条
        PageHelper.startPage(pageCurrent,pageSize,orderBy);

        List<Apply> list=mapper.findAll(entity);
        if(list.size()==0){
            throw new AMException(ExceptionEnum.Apply_NOT_FOUND);
        }
        //丢给pageInfo处理，拿到总条数，页数，页码等等
        PageInfo<Apply> pageInfo=new PageInfo<>(list);
        return pageInfo;
    }

    //这里后期还需要加登录用户的id，用来设置审核人员id
    public void applyPass(Apply apply) throws IOException, URISyntaxException {
        //设置申请的状态为:审核通过；设置批语
        mapper.applyPass(apply);
        //然后需要给这个申请所属的用户，加他申请的service或者dataset的id所对应的权限组
        //首先需要拿到他所申请的service或dataset对应的用户组
        String setId=null;
        if(!StringUtils.isEmpty(apply.getDatasetId())&&!StringUtils.isEmpty(apply.getSetId())){
            //如果这两个id都不为null，报错
            throw new AMException(ExceptionEnum.Apply_SETID_DATASETID_BOTH_NOT_NULL);
        }else if(!StringUtils.isEmpty(apply.getSetId())){
            //如果这个申请是对于数据集的申请
            setId=apply.getSetId();
            /*String setId=apply.getSetId();
            //拿到这个service下的所有插件
            List<Plugin> servicePlugins = pluginService.findServicePlugins(setId);
            Plugin rateLimit=null;
            Plugin acl=null;
            Plugin keyAuth=null;
            for(Plugin temp:servicePlugins){
                if (temp.getName().equals("rate-limiting"))
                    rateLimit=temp;
                else if(temp.getName().equals("acl"))
                    acl=temp;
                else if(temp.getName().equals("key-auth"))
                    keyAuth=temp;
            }
            //获取这个service所对应的用户组
            List<String> allow = (List<String>) acl.getConfig().get("allow");
            //给用户添加上用户组
            //默认只添加第一个组
            consumerService.addGroup(apply.getUserId(),allow.get(0));
            //然后需要判断这个用户有没有秘钥，如果没有的话需要创建一个秘钥
            List<KeyAuthCredential> consumerKeyAuth = consumerService.getConsumerKeyAuth(apply.getUserId());
            if(consumerKeyAuth.size()<1){
                //创建秘钥
                consumerService.generateKeyForConsumer(apply.getUserId());
            }*/
            //然后需要为这个servcie和用户绑定rate-limit插件
            consumerBindRateLimit(apply.getUserId(),apply.getTimes(),apply.getSetId());
            //更新申请表中申请的状态
            //mapper.passSetsById(apply.getSetId());
            //设置其他对这个接口集的还是待审核状态的申请为已失效
            mapper.setShiXiaoById(apply.getSetId());
        }else{
            //如果是对数据块的申请
            setId=apply.getDatasetId();
            //更新申请表中申请的状态
            //mapper.passDatasetById(setId);
            //设置其他对这个数据块的处于审批中状态的申请，为已失效
            mapper.datasetShiXiaoById(setId);
        }
        //String setId=apply.getSetId();
        //拿到这个service下的所有插件
        List<Plugin> servicePlugins = pluginService.findServicePlugins(setId);
        Plugin rateLimit=null;
        Plugin acl=null;
        Plugin keyAuth=null;

        for(Plugin temp:servicePlugins){
            if (temp.getName().equals("rate-limiting"))
                rateLimit=temp;
            else if(temp.getName().equals("acl"))
                acl=temp;
            else if(temp.getName().equals("key-auth"))
                keyAuth=temp;
        }
        if(acl==null){
            //如果这个service没有绑定acl插件
            //那么就给他绑定acl插件
            acl=apiService.bindAcl(setId);
        }
        if(keyAuth==null){
            //如果这个service的keyauth插件为null,就为他绑定key-auth插件
            keyAuth=apiService.bindKeyAuth(setId);
        }
        //获取这个service所对应的用户组
        List<String> allow = (List<String>) acl.getConfig().get("allow");
        //给用户添加上用户组
        //默认只添加第一个组
        try {
            consumerService.addGroup(apply.getUserId(), allow.get(0));
        }catch (NetContextException e){
            //如果客户已经添加过这个用户组了，那么捕获这个报错异常
            logger.info(e.getNetContextEum().getMessage());
        }
        //然后需要判断这个用户有没有秘钥，如果没有的话需要创建一个秘钥
        List<KeyAuthCredential> consumerKeyAuth = consumerService.getConsumerKeyAuth(apply.getUserId());
        if(consumerKeyAuth.size()<1){
            //创建秘钥
            consumerService.generateKeyForConsumer(apply.getUserId());
        }
    }
    //给用户绑定rateLimit插件，time是每月使用这个service的次数
    public void consumerBindRateLimit(String consumerId,int times,String serviceId) throws IOException, URISyntaxException {
        Map<String,Object> config=new HashMap<>();
        config.put("month",times);
        Plugin rateLimiting = new Plugin.Builder("rate-limiting")
                .setConsumer(new Plugin.Consumer(consumerId))
                .setService(new Plugin.Service(serviceId))
                .setConfig(config).builder();
        //kongPlugin.addPlugin(rateLimiting);
        try{
            kongPlugin.addPluginAndJudge(rateLimiting, KongOperationType.PLUGIN_ADD);
        }catch(NetContextException e){
            //如果已经绑定过rate-Limitin插件
            logger.info("用户或service已经绑定过这个插件"+e.getNetContextEum().getMessage());
            //获取这个用户的所有绑定插件
            List<Plugin> consumerPlugins = consumerService.getConsumerPlugins(consumerId);
            for(Plugin plugin:consumerPlugins){
                if(plugin.getName().equals("rate-limiting")){
                    if(plugin.getService()!=null&&plugin.getService().getId().equals(serviceId)){
                        //如果是针对这个service的id,那么就删除这个plugin
                        pluginService.deletePlugin(plugin.getId());
                        //然后重新绑定插件
                        kongPlugin.addPluginAndJudge(rateLimiting, KongOperationType.PLUGIN_ADD);
                    }
                }
            }
        }
    }

    public void applyReject(Apply apply) {
        //申请id不能为null
        if(StringUtils.isEmpty(apply))
            throw new AMException(ExceptionEnum.ID_IS_NULL);
        if(apply.getState()!=1){
            throw new AMException(ExceptionEnum.Apply_REJECT_STATE);
        }
        mapper.applyReject(apply.getId(),apply.getMessage());
    }

    public void updateApply(Apply apply, List<MultipartFile> picFile) {
        if(apply.getId()==null||apply.getId()<1){
            throw new AMException(ExceptionEnum.ID_IS_ERROR);
        }
        if(apply.getState()==null||apply.getState()!=1){
            throw new AMException(ExceptionEnum.Apply_UPDATE_STATE);
        }
        if(picFile!=null&&picFile.size()>0&&picFile.get(0).getSize()!=0){
            //如果有文件就需要更新
            //上传的多张图片需要先存储到服务器
            StringBuilder sb=new StringBuilder("");
            try{
                for(MultipartFile file:picFile){
                    //上传存储图片，返回的是存储的最终路径
                    //多个图片存储的路径用;分割
                    sb.append(apiService.SaveFile(file)).append(";");
                }
            }catch (StringIndexOutOfBoundsException e){
                throw new AMException(ExceptionEnum.File_NOT_UPLOAD);
            }
            apply.setPicUrls(sb.toString());
        }
        //更新时间
        apply.setDate(new Date());
        mapper.updateApply(apply);
    }
}
